package com.cskaoyan.java.object._6clone;

/**
 * clone方法的方法声明为：
 *      protected native Object clone() throws CloneNotSupportedException;
 * 这里需要注意的地方有：
 *      1.首先注意访问权限，它的访问权限是protected。这意味着：
 *          一般来说，只能在子类当中，创建子类自身对象才能够调用该方法
 *          （方法调用位置，肯定不是同包）。
 *          让一个类自身克隆自身，一般都没有多大意义，所以建议在子类中重写方法访问权限。
 *      2.它是一个本地native方法，没有方法体。（依赖本地方法实现创建对象，不同于new对象）
 *      3.返回值类型是Object。
 *      4.throws CloneNotSupportedException是方法抛出异常的声明，这里我们先不管，后面异常的章节会讲解。
 *
 *
 * 方法的作用:
 *      和它的名字一样,该方法需要一个对象来调用,作用是克隆,复制一份该对象
 *          该方法通过一个本地方法来创建一个新的对象,这种创建对象的方式完全不同于new对象
 *          这是一种新的独特的创建对象的方式
 *      在Java当中,创建对象的方式:
 *          1.new对象
 *          2.clone方法
 *
 *
 * 如何使用该方法克隆某个类的对象呢?
 *      1,克隆对象一般不会在自身类当中自己克隆自己,所以为了能够在其他类中调用clone方法
 *      第一步是需要突破访问权限的限制,需要子类重写clone方法的访问权限(这一步是必须的)
 *
 *      2.通过Object类默认实现的clone方法获取的对象一定和原先的对象类型一致,属性等完全相同
 *       所以推荐在重写访问权限时,顺手重写方法的返回值类型为自身类型(这一步不是必须的)
 *
 *      3.在java当中,某个类要想做clone操作,必须实现接口"java.lang.Cloneable"
 *      如果不实现该接口,强行调用clone方法,就会抛出异常CloneNotSupportedException 程序终止(这一步是必须的)
 *
 * 注意事项:
 *      1.clone方法是一种新的独立的创建对象的方式,完全独立于new对象,它不依赖于构造器
 *      2.(重点)Cloneable接口是一个什么接口?
 *          是一个空接口,是一个标记接口
 *
 * 总的来说,clone方法是非常少用的,大家仅做了解
 * 但是clone方法毕竟是创建对象的一种方式,请大家知道这个方法
 *
 * @since 17:08
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student s = new Student(18, 100);
        // cloneStu是和s对象完全一致的,独立的新对象
        Student cloneStu = s.clone();

        System.out.println(s.equals(cloneStu));
        System.out.println(s == cloneStu);
    }
}
// interface Cloneable{}
interface MyCloneable extends Cloneable{}

class Student implements MyCloneable{
    int age;
    double score;

    public Student(int age, double score) {
        this.age = age;
        this.score = score;
        // System.out.println("hello");
    }

    @Override
    protected Student clone() throws CloneNotSupportedException {
        return (Student) super.clone();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (age != student.age) return false;
        return Double.compare(student.score, score) == 0;
    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        result = age;
        temp = Double.doubleToLongBits(score);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }
}
